//! Function system for template processing
//! 
//! This module provides a comprehensive function registry and execution system
//! for template functions, compatible with HttpRunner's function system.

use crate::error::{Error, Result};
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;

/// Function trait for template functions
pub trait Function: Send + Sync {
    /// Execute the function with given arguments
    fn call(&self, args: &[Value]) -> Result<Value>;
    
    /// Get function name
    fn name(&self) -> &str;
    
    /// Get function description
    fn description(&self) -> &str {
        "No description available"
    }
    
    /// Get expected argument count (None for variable arguments)
    fn arg_count(&self) -> Option<usize> {
        None
    }
    
    /// Validate function arguments
    fn validate_args(&self, args: &[Value]) -> Result<()> {
        if let Some(expected_count) = self.arg_count() {
            if args.len() != expected_count {
                return Err(Error::Internal(format!(
                    "Function '{}' expects {} arguments, got {}",
                    self.name(),
                    expected_count,
                    args.len()
                )));
            }
        }
        Ok(())
    }
}

/// Function call structure
#[derive(Debug, Clone)]
pub struct FunctionCall {
    /// Function name
    pub name: String,
    
    /// Function arguments
    pub args: Vec<Value>,
}

/// Function registry for managing template functions
pub struct FunctionRegistry {
    /// Registered functions
    functions: HashMap<String, Arc<dyn Function>>,
    
    /// Function call statistics
    stats: FunctionStats,
}

/// Function call statistics
#[derive(Debug, Clone, Default)]
pub struct FunctionStats {
    /// Total function calls
    pub total_calls: usize,
    
    /// Successful function calls
    pub successful_calls: usize,
    
    /// Failed function calls
    pub failed_calls: usize,
    
    /// Function call counts by name
    pub call_counts: HashMap<String, usize>,
    
    /// Function execution errors
    pub errors: Vec<String>,
}

impl FunctionRegistry {
    /// Create a new function registry with built-in functions
    pub fn new() -> Self {
        let mut registry = Self {
            functions: HashMap::new(),
            stats: FunctionStats::default(),
        };
        
        // Register built-in functions
        registry.register_builtin_functions();
        
        registry
    }
    
    /// Register a function
    pub fn register<F>(&mut self, function: F) -> Result<()>
    where
        F: Function + 'static,
    {
        let name = function.name().to_string();
        self.functions.insert(name, Arc::new(function));
        Ok(())
    }
    
    /// Call a function by name
    pub fn call(&mut self, function_call: &FunctionCall) -> Result<Value> {
        self.stats.total_calls += 1;
        
        if let Some(function) = self.functions.get(&function_call.name) {
            // Validate arguments
            function.validate_args(&function_call.args)?;
            
            // Execute function
            match function.call(&function_call.args) {
                Ok(result) => {
                    self.stats.successful_calls += 1;
                    *self.stats.call_counts.entry(function_call.name.clone()).or_insert(0) += 1;
                    Ok(result)
                }
                Err(e) => {
                    self.stats.failed_calls += 1;
                    self.stats.errors.push(format!("Function '{}' failed: {}", function_call.name, e));
                    Err(e)
                }
            }
        } else {
            self.stats.failed_calls += 1;
            let error_msg = format!("Function '{}' not found", function_call.name);
            self.stats.errors.push(error_msg.clone());
            Err(Error::Internal(error_msg))
        }
    }
    
    /// Check if a function is registered
    pub fn has_function(&self, name: &str) -> bool {
        self.functions.contains_key(name)
    }
    
    /// List all registered function names
    pub fn list_functions(&self) -> Vec<String> {
        self.functions.keys().cloned().collect()
    }
    
    /// Get function statistics
    pub fn stats(&self) -> &FunctionStats {
        &self.stats
    }
    
    /// Reset statistics
    pub fn reset_stats(&mut self) {
        self.stats = FunctionStats::default();
    }
    
    /// Register built-in functions
    fn register_builtin_functions(&mut self) {
        // Math functions
        self.register(SumFunction).unwrap();
        self.register(MaxFunction).unwrap();
        self.register(MinFunction).unwrap();
        self.register(AbsFunction).unwrap();
        
        // String functions
        self.register(ConcatFunction).unwrap();
        self.register(UpperFunction).unwrap();
        self.register(LowerFunction).unwrap();
        self.register(TrimFunction).unwrap();
        
        // Utility functions
        self.register(RandomIntFunction).unwrap();
        self.register(RandomStringFunction).unwrap();
        self.register(TimestampFunction).unwrap();
        self.register(UuidFunction).unwrap();

        // HttpRunner compatible functions
        self.register(GetTimestampFunction).unwrap();
        self.register(SleepFunction).unwrap();
        self.register(SetupHookFunction).unwrap();
        self.register(TeardownHookFunction).unwrap();
    }
}

impl Default for FunctionRegistry {
    fn default() -> Self {
        Self::new()
    }
}

// Built-in function implementations

/// Sum function - adds numeric values
struct SumFunction;

impl Function for SumFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        let mut sum = 0.0;
        for arg in args {
            match arg {
                Value::Number(n) => {
                    if let Some(f) = n.as_f64() {
                        sum += f;
                    } else {
                        return Err(Error::Internal("Invalid number in sum function".to_string()));
                    }
                }
                _ => return Err(Error::Internal("Sum function requires numeric arguments".to_string())),
            }
        }
        Ok(Value::Number(serde_json::Number::from_f64(sum).unwrap()))
    }
    
    fn name(&self) -> &str {
        "sum"
    }
    
    fn description(&self) -> &str {
        "Sum numeric values"
    }
}

/// Max function - returns maximum value
struct MaxFunction;

impl Function for MaxFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        if args.is_empty() {
            return Err(Error::Internal("Max function requires at least one argument".to_string()));
        }
        
        let mut max = f64::NEG_INFINITY;
        for arg in args {
            match arg {
                Value::Number(n) => {
                    if let Some(f) = n.as_f64() {
                        if f > max {
                            max = f;
                        }
                    } else {
                        return Err(Error::Internal("Invalid number in max function".to_string()));
                    }
                }
                _ => return Err(Error::Internal("Max function requires numeric arguments".to_string())),
            }
        }
        Ok(Value::Number(serde_json::Number::from_f64(max).unwrap()))
    }
    
    fn name(&self) -> &str {
        "max"
    }
    
    fn description(&self) -> &str {
        "Return maximum value"
    }
}

/// Min function - returns minimum value
struct MinFunction;

impl Function for MinFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        if args.is_empty() {
            return Err(Error::Internal("Min function requires at least one argument".to_string()));
        }
        
        let mut min = f64::INFINITY;
        for arg in args {
            match arg {
                Value::Number(n) => {
                    if let Some(f) = n.as_f64() {
                        if f < min {
                            min = f;
                        }
                    } else {
                        return Err(Error::Internal("Invalid number in min function".to_string()));
                    }
                }
                _ => return Err(Error::Internal("Min function requires numeric arguments".to_string())),
            }
        }
        Ok(Value::Number(serde_json::Number::from_f64(min).unwrap()))
    }
    
    fn name(&self) -> &str {
        "min"
    }
    
    fn description(&self) -> &str {
        "Return minimum value"
    }
}

/// Abs function - returns absolute value
struct AbsFunction;

impl Function for AbsFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        if args.len() != 1 {
            return Err(Error::Internal("Abs function requires exactly one argument".to_string()));
        }
        
        match &args[0] {
            Value::Number(n) => {
                if let Some(f) = n.as_f64() {
                    Ok(Value::Number(serde_json::Number::from_f64(f.abs()).unwrap()))
                } else {
                    Err(Error::Internal("Invalid number in abs function".to_string()))
                }
            }
            _ => Err(Error::Internal("Abs function requires numeric argument".to_string())),
        }
    }
    
    fn name(&self) -> &str {
        "abs"
    }
    
    fn description(&self) -> &str {
        "Return absolute value"
    }
    
    fn arg_count(&self) -> Option<usize> {
        Some(1)
    }
}

/// Concat function - concatenates strings
struct ConcatFunction;

impl Function for ConcatFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        let mut result = String::new();
        for arg in args {
            match arg {
                Value::String(s) => result.push_str(s),
                Value::Number(n) => result.push_str(&n.to_string()),
                Value::Bool(b) => result.push_str(&b.to_string()),
                _ => result.push_str(&serde_json::to_string(arg).unwrap_or_default()),
            }
        }
        Ok(Value::String(result))
    }
    
    fn name(&self) -> &str {
        "concat"
    }
    
    fn description(&self) -> &str {
        "Concatenate values as strings"
    }
}

/// Upper function - converts string to uppercase
struct UpperFunction;

impl Function for UpperFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        if args.len() != 1 {
            return Err(Error::Internal("Upper function requires exactly one argument".to_string()));
        }
        
        match &args[0] {
            Value::String(s) => Ok(Value::String(s.to_uppercase())),
            _ => Err(Error::Internal("Upper function requires string argument".to_string())),
        }
    }
    
    fn name(&self) -> &str {
        "upper"
    }
    
    fn description(&self) -> &str {
        "Convert string to uppercase"
    }
    
    fn arg_count(&self) -> Option<usize> {
        Some(1)
    }
}

/// Lower function - converts string to lowercase
struct LowerFunction;

impl Function for LowerFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        if args.len() != 1 {
            return Err(Error::Internal("Lower function requires exactly one argument".to_string()));
        }
        
        match &args[0] {
            Value::String(s) => Ok(Value::String(s.to_lowercase())),
            _ => Err(Error::Internal("Lower function requires string argument".to_string())),
        }
    }
    
    fn name(&self) -> &str {
        "lower"
    }
    
    fn description(&self) -> &str {
        "Convert string to lowercase"
    }
    
    fn arg_count(&self) -> Option<usize> {
        Some(1)
    }
}

/// Trim function - trims whitespace from string
struct TrimFunction;

impl Function for TrimFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        if args.len() != 1 {
            return Err(Error::Internal("Trim function requires exactly one argument".to_string()));
        }
        
        match &args[0] {
            Value::String(s) => Ok(Value::String(s.trim().to_string())),
            _ => Err(Error::Internal("Trim function requires string argument".to_string())),
        }
    }
    
    fn name(&self) -> &str {
        "trim"
    }
    
    fn description(&self) -> &str {
        "Trim whitespace from string"
    }
    
    fn arg_count(&self) -> Option<usize> {
        Some(1)
    }
}

/// Random integer function
struct RandomIntFunction;

impl Function for RandomIntFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        use rand::Rng;
        
        let (min, max) = match args.len() {
            0 => (0, 100),
            1 => {
                if let Value::Number(n) = &args[0] {
                    if let Some(max_val) = n.as_i64() {
                        (0, max_val)
                    } else {
                        return Err(Error::Internal("Invalid number in random_int function".to_string()));
                    }
                } else {
                    return Err(Error::Internal("Random_int function requires numeric argument".to_string()));
                }
            }
            2 => {
                let min_val = if let Value::Number(n) = &args[0] {
                    n.as_i64().ok_or_else(|| Error::Internal("Invalid min value".to_string()))?
                } else {
                    return Err(Error::Internal("Random_int function requires numeric arguments".to_string()));
                };
                
                let max_val = if let Value::Number(n) = &args[1] {
                    n.as_i64().ok_or_else(|| Error::Internal("Invalid max value".to_string()))?
                } else {
                    return Err(Error::Internal("Random_int function requires numeric arguments".to_string()));
                };
                
                (min_val, max_val)
            }
            _ => return Err(Error::Internal("Random_int function accepts 0-2 arguments".to_string())),
        };
        
        let mut rng = rand::thread_rng();
        let random_value = rng.gen_range(min..=max);
        Ok(Value::Number(random_value.into()))
    }
    
    fn name(&self) -> &str {
        "random_int"
    }
    
    fn description(&self) -> &str {
        "Generate random integer"
    }
}

/// Random string function
struct RandomStringFunction;

impl Function for RandomStringFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        use rand::{Rng, distributions::Alphanumeric};
        
        let length = if args.is_empty() {
            10
        } else if let Value::Number(n) = &args[0] {
            n.as_u64().ok_or_else(|| Error::Internal("Invalid length value".to_string()))? as usize
        } else {
            return Err(Error::Internal("Random_string function requires numeric length".to_string()));
        };
        
        let random_string: String = rand::thread_rng()
            .sample_iter(&Alphanumeric)
            .take(length)
            .map(char::from)
            .collect();
        
        Ok(Value::String(random_string))
    }
    
    fn name(&self) -> &str {
        "random_string"
    }
    
    fn description(&self) -> &str {
        "Generate random string"
    }
}

/// Timestamp function
struct TimestampFunction;

impl Function for TimestampFunction {
    fn call(&self, _args: &[Value]) -> Result<Value> {
        let timestamp = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_secs();
        Ok(Value::Number(timestamp.into()))
    }
    
    fn name(&self) -> &str {
        "timestamp"
    }
    
    fn description(&self) -> &str {
        "Get current Unix timestamp"
    }
    
    fn arg_count(&self) -> Option<usize> {
        Some(0)
    }
}

/// UUID function
struct UuidFunction;

impl Function for UuidFunction {
    fn call(&self, _args: &[Value]) -> Result<Value> {
        let uuid = uuid::Uuid::new_v4().to_string();
        Ok(Value::String(uuid))
    }
    
    fn name(&self) -> &str {
        "uuid"
    }
    
    fn description(&self) -> &str {
        "Generate UUID v4"
    }
    
    fn arg_count(&self) -> Option<usize> {
        Some(0)
    }
}

// HttpRunner compatible functions

/// Get timestamp function (HttpRunner compatible)
struct GetTimestampFunction;

impl Function for GetTimestampFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        let timestamp = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_secs();

        if args.is_empty() {
            Ok(Value::Number(timestamp.into()))
        } else if let Value::String(format) = &args[0] {
            // Support basic timestamp formatting
            match format.as_str() {
                "ms" => {
                    let timestamp_ms = std::time::SystemTime::now()
                        .duration_since(std::time::UNIX_EPOCH)
                        .unwrap()
                        .as_millis() as u64; // Convert to u64 which is supported
                    Ok(Value::Number(timestamp_ms.into()))
                }
                _ => Ok(Value::Number(timestamp.into()))
            }
        } else {
            Ok(Value::Number(timestamp.into()))
        }
    }

    fn name(&self) -> &str {
        "get_timestamp"
    }

    fn description(&self) -> &str {
        "Get current timestamp (HttpRunner compatible)"
    }
}

/// Sleep function (for testing purposes)
struct SleepFunction;

impl Function for SleepFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        if args.len() != 1 {
            return Err(Error::Internal("Sleep function requires exactly one argument".to_string()));
        }

        if let Value::Number(n) = &args[0] {
            if let Some(seconds) = n.as_f64() {
                // Note: In a real implementation, you might want to use async sleep
                // For now, we'll just return the sleep duration
                Ok(Value::String(format!("sleep({})", seconds)))
            } else {
                Err(Error::Internal("Invalid sleep duration".to_string()))
            }
        } else {
            Err(Error::Internal("Sleep function requires numeric argument".to_string()))
        }
    }

    fn name(&self) -> &str {
        "sleep"
    }

    fn description(&self) -> &str {
        "Sleep for specified seconds"
    }

    fn arg_count(&self) -> Option<usize> {
        Some(1)
    }
}

/// Setup hook function (placeholder for HttpRunner compatibility)
struct SetupHookFunction;

impl Function for SetupHookFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        // This is a placeholder - in a real implementation, this would
        // execute setup hooks before test execution
        Ok(Value::String(format!("setup_hook({:?})", args)))
    }

    fn name(&self) -> &str {
        "setup_hook"
    }

    fn description(&self) -> &str {
        "Execute setup hook (HttpRunner compatible)"
    }
}

/// Teardown hook function (placeholder for HttpRunner compatibility)
struct TeardownHookFunction;

impl Function for TeardownHookFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        // This is a placeholder - in a real implementation, this would
        // execute teardown hooks after test execution
        Ok(Value::String(format!("teardown_hook({:?})", args)))
    }

    fn name(&self) -> &str {
        "teardown_hook"
    }

    fn description(&self) -> &str {
        "Execute teardown hook (HttpRunner compatible)"
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_function_registry_creation() {
        let registry = FunctionRegistry::new();
        let functions = registry.list_functions();
        
        // Should have built-in functions
        assert!(functions.contains(&"sum".to_string()));
        assert!(functions.contains(&"max".to_string()));
        assert!(functions.contains(&"min".to_string()));
        assert!(functions.contains(&"concat".to_string()));
    }

    #[test]
    fn test_sum_function() {
        let mut registry = FunctionRegistry::new();
        let call = FunctionCall {
            name: "sum".to_string(),
            args: vec![
                Value::Number(10.into()),
                Value::Number(20.into()),
                Value::Number(30.into()),
            ],
        };
        
        let result = registry.call(&call).unwrap();
        // 注意：serde_json可能将数字解析为f64
        match result {
            Value::Number(n) => {
                if n.is_f64() {
                    assert_eq!(n.as_f64().unwrap(), 60.0);
                } else {
                    assert_eq!(n.as_i64().unwrap(), 60);
                }
            }
            _ => panic!("Expected number result"),
        }
    }

    #[test]
    fn test_max_function() {
        let mut registry = FunctionRegistry::new();
        let call = FunctionCall {
            name: "max".to_string(),
            args: vec![
                Value::Number(10.into()),
                Value::Number(30.into()),
                Value::Number(20.into()),
            ],
        };
        
        let result = registry.call(&call).unwrap();
        // 注意：serde_json可能将数字解析为f64
        match result {
            Value::Number(n) => {
                if n.is_f64() {
                    assert_eq!(n.as_f64().unwrap(), 30.0);
                } else {
                    assert_eq!(n.as_i64().unwrap(), 30);
                }
            }
            _ => panic!("Expected number result"),
        }
    }

    #[test]
    fn test_concat_function() {
        let mut registry = FunctionRegistry::new();
        let call = FunctionCall {
            name: "concat".to_string(),
            args: vec![
                Value::String("Hello".to_string()),
                Value::String(" ".to_string()),
                Value::String("World".to_string()),
            ],
        };
        
        let result = registry.call(&call).unwrap();
        assert_eq!(result, Value::String("Hello World".to_string()));
    }

    #[test]
    fn test_random_functions() {
        let mut registry = FunctionRegistry::new();
        
        // Test random_int
        let call = FunctionCall {
            name: "random_int".to_string(),
            args: vec![Value::Number(1.into()), Value::Number(10.into())],
        };
        let result = registry.call(&call).unwrap();
        if let Value::Number(n) = result {
            let val = n.as_i64().unwrap();
            assert!(val >= 1 && val <= 10);
        } else {
            panic!("Expected number result");
        }
        
        // Test random_string
        let call = FunctionCall {
            name: "random_string".to_string(),
            args: vec![Value::Number(5.into())],
        };
        let result = registry.call(&call).unwrap();
        if let Value::String(s) = result {
            assert_eq!(s.len(), 5);
        } else {
            panic!("Expected string result");
        }
    }

    #[test]
    fn test_function_statistics() {
        let mut registry = FunctionRegistry::new();
        let call = FunctionCall {
            name: "sum".to_string(),
            args: vec![Value::Number(1.into()), Value::Number(2.into())],
        };
        
        registry.call(&call).unwrap();
        registry.call(&call).unwrap();
        
        let stats = registry.stats();
        assert_eq!(stats.total_calls, 2);
        assert_eq!(stats.successful_calls, 2);
        assert_eq!(stats.failed_calls, 0);
        assert_eq!(stats.call_counts.get("sum"), Some(&2));
    }
}
